package com.lgw.coupon.handler;

import com.lgw.commons.model.domain.ResultInfo;
import com.lgw.commons.utils.ResultInfoUtil;
import com.lgw.coupon.annotation.RateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;


/**
 * 选择织入的位置
 */
@Slf4j
@Component
@Aspect
public class RateLimiterHandler {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private HttpServletRequest httpServletRequest;

    private DefaultRedisScript<Long> limitScript;

    //读取lua脚本
    @PostConstruct
    public void init() {
        limitScript = new DefaultRedisScript<>();
        limitScript.setResultType(Long.class);
        limitScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("limit.lua")));
    }

    /**
     * 切入点表达式
     */
    @Pointcut("@annotation(com.lgw.coupon.annotation.RateLimiter)")
    public void rateLimiter(){}

    //对秒杀方法进行限流
    @Around("@annotation(rateLimiter)")
    public Object limit(ProceedingJoinPoint proceedingJoinPoint, RateLimiter rateLimiter) throws Throwable {
        log.info("进入秒杀限流");
        // 限流模块key
        String limitKey = String.valueOf(System.currentTimeMillis()/1000);
        // 限制通过请求
        long limitTimes = rateLimiter.limit();
        // 限流超时时间为秒
        long expireTime = rateLimiter.expire();
//        log.debug("RateLimterHandler[分布式限流处理器]参数值为-limitTimes={},limitTimeout={}", limitTimes, expireTime);
        String message = rateLimiter.message();
//        if (StringUtils.isBlank(message)) {
//            message = "false";
//        }

        List<String> keyList = new ArrayList<>();
        keyList.add(limitKey);
        Long result = (Long) redisTemplate.execute(limitScript, keyList, expireTime, limitTimes);
        if (result == 0) {
            String msg = "由于超过单位时间=" + expireTime + "-允许的请求次数=" + limitTimes + "[触发限流]";
            log.info(msg);
            return ResultInfoUtil.buildError(0,httpServletRequest.getServletPath(),msg);
        }
        log.debug("RateLimterHandler[分布式限流处理器]限流执行结果-result={},请求[正常]响应", result);
        //让目标方法执行
        return proceedingJoinPoint.proceed();
    }
}
